<template>
    <div class="wrapper">
        <div id="container" ref="container"></div>
        <div class="btn-list">
            <button class="btn" @click="addNode({})">add</button>
            <button class="btn" @click="format">格式化</button>
            <button class="btn" @click="save">保存</button>
        </div>
    </div>
</template>

<script>
import { Graph, Model } from "@antv/x6";
import { DagreLayout } from "@antv/layout";

export default {
    name: "",
    data () {
        return {
            graph: null,
            nodes: [],
            edges: [],
            node_width: 160,
            node_height: 32,
            currDir: "",
            portAttrs: {
                circle: {
                    magnet: true,
                    r: 3,
                    stroke: "#31d0c6",
                    strokeWidth: 2,
                    fill: "#fff",
                    style: {
                        visibility: "hidden"
                    }
                }
            }
        };
    },
    methods: {
        // mock一些数据
        mockData () {
            // this.graphData = JSON.parse(localStorage.getItem("graphData"));
            // if (this.graphData) {
            //     this.nodes = this.graphData.nodesArr;
            //     this.edges = this.graphData.edgesArr;
            //     return;
            // }
            for (let i = 1; i <= 7; i++) {
                this.nodes.push({
                    id: `node${i}`,
                    label: `节点${i}`,
                    x: this.node_width * (i - 1) + 20 * i,
                    y: 100
                });
            }

            this.edges = [
                { source: "node1", target: "node3" },
                { source: "node2", target: "node3" },
                { source: "node3", target: "node4" },
                { source: "node3", target: "node5" },
                { source: "node1", target: "node5" },
                { source: "node4", target: "node6" },
                { source: "node4", target: "node7" },
                { source: "node1", target: "node7" }

                // { source: "node1", target: "node2" },
                // { source: "node1", target: "node4" },
                // { source: "node1", target: "node5" },
                // { source: "node1", target: "node8" },
                // { source: "node2", target: "node7" },
                // { source: "node3", target: "node7" },
                // { source: "node4", target: "node8" },
                // { source: "node5", target: "node10" },
                // { source: "node6", target: "node10" },
                // { source: "node7", target: "node11" },
                // { source: "node7", target: "node12" },
                // { source: "node9", target: "node12" },
                // { source: "node12", target: "node13" },
                // { source: "node13", target: "node14" }
            ];
        },
        // graph初始化
        initGraph () {
            this.graph = new Graph({
                container: this.$refs.container,
                width: 1300,
                height: 800,
                // frozen: true,
                grid: {
                    size: 10,
                    visible: true
                },
                // snapline: false,
                panning: true,
                connecting: {
                    router: {
                        name: "manhattan"
                    }
                }
            });
            // 注册事件
            this.registEvents();
            // 新增节点
            this.nodes.forEach(item => {
                this.addNode(item);
            });
            // 新增边
            this.addEdge();
            // 格式化节点
            // this.setDagreLayout();
        },
        // 新增节点
        addNode (item) {
            this.graph.addNode({
                id: item.id || `node${this.nodes.length + 1}`,
                x: item.x || 0,
                y: item.y || 0,
                width: this.node_width,
                height: this.node_height,
                label: item.label || `节点${this.nodes.length + 1}`,
                attrs: {
                    body: {
                        fill: "#f5f5f5",
                        stroke: "#d9d9d9",
                        strokeWidth: 1
                    },
                    label: {
                        fontSize: 12
                    }
                },
                ports: {
                    groups: {
                        top: {
                            attrs: this.portAttrs,
                            position: {
                                name: "top"
                            }
                        },
                        right: {
                            attrs: this.portAttrs,
                            position: {
                                name: "right"
                            }
                        },
                        bottom: {
                            attrs: this.portAttrs,
                            position: {
                                name: "bottom"
                            }
                        },
                        left: {
                            attrs: this.portAttrs,
                            position: {
                                name: "left"
                            }
                        }
                    },
                    items: [
                        { id: "top", group: "top" },
                        { id: "right", group: "right" },
                        { id: "bottom", group: "bottom" },
                        { id: "left", group: "left" }
                    ]
                }
            });
        },
        // 新增边
        addEdge () {
            this.edges.forEach(edge => {
                this.graph.addEdge({
                    source: edge.source,
                    target: edge.target,
                    vertices: edge.vertices || {},
                    router: {
                        // name: "manhattan"
                    },
                    connector: {
                    }
                });
            });
        },
        // Dagre布局
        setDagreLayout () {
            const config = {};
            if (this.currDir === "LR") {
                config.ranksep = 70;
                config.nodesep = 15;
            } else if (this.currDir === "TB") {
                config.ranksep = 20;
                config.nodesep = 60;
            }
            const dagreLayout = new DagreLayout({
                type: "dagre",
                rankdir: this.currDir,
                ranksep: config.ranksep,
                align: "UL",
                nodesep: config.nodesep
            });
            const nodesArr = this.graph.getNodes();
            const nodes = nodesArr.map(node => ({ id: node.id, label: node.label }));
            const edges = this.graph.getEdges();
            // Dagre布局
            const model = dagreLayout.layout({ nodes, edges });
            // 各节点调整位置
            nodesArr.forEach(node => {
                const dagreNode = model.nodes.find(val => val.id === node.id);
                if (dagreNode) {
                    node.position(dagreNode.x, dagreNode.y);
                }
            });
            // 更新连线
            this.updateEdges();
            // 更新连线 - 指定连接桩
            // this.updateEdgesByports();
        },
        // 更新连线
        updateEdges () {
            this.graph.getEdges().forEach(edge => {
                // 获取连线起始node
                const sourceNode = this.graph.getCellById(edge.source.cell);
                const targetNode = this.graph.getCellById(edge.target.cell);
                // 获取起止元素中心点坐标
                const nodeSourceX = sourceNode.position().x + this.node_width / 2;
                const nodeSourceY = sourceNode.position().y + this.node_height / 2;
                const nodeTargetX = targetNode.position().x + this.node_width / 2;
                const nodeTargetY = targetNode.position().y + this.node_height / 2;
                /**
                 * 设置拐点
                 */
                // LR布局
                let p1 = {};
                let p2 = {};
                if (this.currDir === "LR") {
                    p1 = { x: (nodeSourceX + nodeTargetX) / 2, y: nodeSourceY };
                    p2 = { x: (nodeSourceX + nodeTargetX) / 2, y: nodeTargetY };
                    edge.setVertices([p1, p2]);
                // TB布局
                } else if (this.currDir === "TB") {
                    p1 = { x: nodeSourceX, y: (nodeSourceY + nodeTargetY) / 2 };
                    p2 = { x: nodeTargetX, y: (nodeSourceY + nodeTargetY) / 2 };
                    edge.setVertices([p1, p2]);
                }
                edge.setRouter({
                    name: "orth"
                });

                console.log(edge.getPolyline());
            });
        },
        // 更新连线 - 指定连接桩
        updateEdgesByports () {
            this.graph.getEdges().forEach(edge => {
                // debugger;
                edge.setRouter({
                    name: "manhattan",
                    args: {
                        padding: 20,
                        startDirections: this.currDir === "LR" ? ["left", "right"] : ["top", "bottom"],
                        endDirections: this.currDir === "LR" ? ["left", "right"] : ["top", "bottom"]
                    }
                });
            });
        },
        // 保存
        save () {
            const nodesArr = [];
            const nodes = this.graph.getNodes();
            nodes.forEach(node => {
                nodesArr.push({
                    id: node.id,
                    label: node.label,
                    ...node.position()
                });
            });

            const edgesArr = [];
            const edges = this.graph.getEdges();
            edges.forEach(edge => {
                edgesArr.push({
                    source: edge.getSource().cell,
                    target: edge.getTarget().cell
                    // vertices: edge.getPolyline().points
                });
            });
            const graphData = { nodesArr, edgesArr };
            localStorage.setItem("graphData", JSON.stringify(graphData));
        },
        // 注册一些事件
        registEvents () {
            // 显示/隐藏事件
            const showPorts = (ports, show) => {
                for (let i = 0, len = ports.length; i < len; i++) {
                    ports[i].style.visibility = show ? "visible" : "hidden";
                }
            };
            // 鼠标移入，显示连接桩
            this.graph.on("node:mouseenter", () => {
                const ports = this.$refs.container.querySelectorAll(".x6-port-body");
                showPorts(ports, true);
            });
            // 鼠标移出，隐藏连接桩
            this.graph.on("node:mouseleave", () => {
                const ports = this.$refs.container.querySelectorAll(".x6-port-body");
                showPorts(ports, false);
            });

            // 节点移动
            this.graph.on("node:moving", (node) => {
                // this.updateEdges();
            });

            this.graph.on("edge:connected", ({ isNew, edge }) => {
            });
        },
        // 格式化
        format () {
            this.currDir = this.currDir === "LR" ? "TB" : "LR";
            this.setDagreLayout();
        }
    },
    created () {},
    mounted () {
        this.mockData();
        this.initGraph();
    }
};
</script>

<style scoped>
.wrapper {
    display: flex;
}
.btn-list {
    margin: 0 0 0 10px;
}
.btn {
    display: block;
    width: 50px;
    height: 20px;
    margin: 0 0 10px 0;
}
</style>
